function PDPageObjects(pdDoc){
	this.type = 0; 			// type  0:page  1:form
	this.objectArr = []; 		// instances array
	this.textObjects = [];
	this.genStates = []; 		// instances array
	this.graphStates = []; 		// instances array
	this.textStates = []; 		// instances array
	this.clrStates = []; 		// instances array
	this.clpathStates = []; 	// instances array
	this.position = []; 		
	this.matrix = null; 		// instances array
	this.fontInfo = []; 		// instances array
	
	this.m_matrixArr = []; 		// instances array
	//	this.m_pdPage = null;
	this.m_csImgPath = "";
	this.m_nVersion = 0;
	
	this.imgObjCount = 0;
	this.loadedImgObjCount = 0;
	this.bFinishParseJson = false;
	this.bFinishLoadImgs = false;
	this.callback = null;
	this.caller = null;
	this.m_pdDoc = pdDoc;
	this.m_usedFont = [];

	this.m_Transparency = 0;//a int flag for transparency
	
	this.m_BBox = [];
}

PDPageObjects.prototype.ParseJson = function (arrayData) {
    if (arrayData.length == 0) return null;

    this.type = arrayData[0];
    var i = 0, len = 0;
    var item = null, obj = null;
    // parse page objects
    for (i = 0, len = arrayData[1].length; i < len; i++) {
        item = arrayData[1][i];
        if (1 == item[0]) { // text object
            obj = new TextObj();
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
            this.textObjects.push(obj);
        }
        else if (2 == item[0]) { // image object
            obj = new ImgObj();
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
            this.LoadImage(obj);
        }
        else if (3 == item[0]) { // inline image object
            obj = new InlineImgObj();
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
            this.LoadImage(obj);
        }
        else if (4 == item[0]) { // path object
            obj = new PathObj();
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
        }
        else if (5 == item[0]) { // shading object
            obj = new ShadingObj();
           
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
        }
        else if (6 == item[0]) { // form object
            obj = new FormObj();
            obj.ParseJson(item);
            if ((0 == (obj.position[0] - obj.position[2])) || (0 == (obj.position[1] - obj.position[3])))
                continue;
            this.objectArr.push(obj);
        }
        else {
            continue;
        }
    }
    // parse general states
    for (i = 0, len = arrayData[2].length; i < len; i++) {
        item = arrayData[2][i];
        obj = new PDGeneralState();
        obj.ParseJson(item);
        this.genStates.push(obj);
    }
    // parse clip path states
    if (Object.prototype.toString.call(arrayData[3]) === '[object Array]') {
        for (i = 0, len = arrayData[3].length; i < len; i++) {
            item = arrayData[3][i];

            obj = new PDClipPathState();
            obj.ParseJson(item);
            this.clpathStates.push(obj);



        }
    }


    // parse graph states
    for (i = 0, len = arrayData[4].length; i < len; i++) {
        item = arrayData[4][i];
        obj = new PDGraphState();
        obj.ParseJson(item);
        this.graphStates.push(obj);
    }
    // parse color states
    for (i = 0, len = arrayData[5].length; i < len; i++) {
        item = arrayData[5][i];
        obj = new PDColorState();
        obj.ParseJson(item);
        this.clrStates.push(obj);
    }
    // parse text states
    for (i = 0, len = arrayData[6].length; i < len; i++) {
        item = arrayData[6][i];
        obj = new PDTextState();
        obj.ParseJson(item);
        this.textStates.push(obj);
    }
    this.position = stringArr2NumArr(arrayData[7]);
    // parse matrix
    this.matrix = new PDMatrix();
    var mtxArr = stringArr2NumArr(arrayData[8]);
    this.matrix.Set(mtxArr[0], mtxArr[1], mtxArr[2],
					mtxArr[3], mtxArr[4], mtxArr[5]);
    // parse font info
    for (i = 0, len = arrayData[9].length; i < len; i++) {
        item = arrayData[9][i];
        obj = new FontInfo();
        this.fontInfo.push(obj);
    }
    this.bFinishParseJson = true;
};
PDPageObjects.prototype.GetMatrixByID = function (id) {
    var len = this.m_matrixArr.length;
    if (id < 0 || id >= len) return null;

    return this.m_matrixArr[id];
};
PDPageObjects.prototype.GetGenStateByID = function (id) {
    for (var i = 0; i < this.genStates.length; i++) {
        if (id == this.genStates[i].uID) { return this.genStates[i]; }
    }
    return null;
};
PDPageObjects.prototype.GetGraphStateByID = function (id) {
    var self = this;
    for (var i = 0; i < this.graphStates.length; i++) {
        if (id == this.graphStates[i].uID)
            return this.graphStates[i];
    }
    return null;
};
PDPageObjects.prototype.GetClrStateByID = function (id) {
    for (var i = 0; i < this.clrStates.length; i++) {
        if (id == this.clrStates[i].uID) return this.clrStates[i];
    }
    return null;
};

PDPageObjects.prototype.GetTextStateByID = function (id) {
    for (var i = 0; i < this.textStates.length; i++) {
        if (id == this.textStates[i].uID) return this.textStates[i];
    }
    return null;
};
PDPageObjects.prototype.GetClipPathStateByID = function (id) {
    for (var i = 0; i < this.clpathStates.length; i++) {
        if (id === this.clpathStates[i].uID) return this.clpathStates[i];
    }
    return null;
};
PDPageObjects.prototype.CountClipPathState = function () {
    return this.clpathStates.length;
};
PDPageObjects.prototype.GetClipPathStateByIndex = function (index) {
    if (index < 0 || index >= this.clpathStates.length) return null;
    return this.clpathStates[i];
};

PDPageObjects.prototype.ParseFromBin = function(rd) {
    this.m_nVersion = rd.readInt32();
    this.m_Transparency = rd.readInt32();
	// matrix list
	var nMatrixCnt = rd.readInt32();
	var mtx = null, tempArr;
	for (var i = 0; i < nMatrixCnt; i++) {
		mtx = new PDMatrix();
		tempArr = [];
		for (var j = 0; j < 6; j++) {tempArr.push(rd.readFloat32());}
		mtx.Set(tempArr[0], tempArr[1], tempArr[2], tempArr[3], tempArr[4], tempArr[5]);
		this.m_matrixArr.push(mtx);
	}
	var nGeneralCnt, nClipCnt, nGraphCnt, nClrCnt, nTxtCnt;
	nGeneralCnt = rd.readInt32();
	nClipCnt = rd.readInt32();
	nGraphCnt = rd.readInt32();
	nClrCnt = rd.readInt32();
	nTxtCnt = rd.readInt32();
	var dwGeneralOffset, dwClipOffset, dwGraphOffset, dwClrOffset, dwTxtOffset;
	dwGeneralOffset = rd.readUint32();
	dwClipOffset = rd.readUint32();
	dwGraphOffset = rd.readUint32();
	dwClrOffset = rd.readUint32();
	dwTxtOffset = rd.readUint32();
	var dwContentOffset = rd.readInt32();
	var state = null, obj = null;
	for (var i = 0; i < nGeneralCnt; i++) {
		state = new PDGeneralState(this);
		state.ParseFromBin(rd);
		this.genStates.push(state);
	}
	for (var i = 0; i < nClipCnt; i++) {
	    state = new PDClipPathState(this);
		state.ParseFromBin(rd);
		this.clpathStates.push(state);
	}
	for (var i = 0; i < nGraphCnt; i++) {
		state = new PDGraphState();
		state.ParseFromBin(rd);
		this.graphStates.push(state);
	}
	for (var i = 0; i < nClrCnt; i++) {
	    state = new PDColorState(this);
		state.ParseFromBin(rd);
		this.clrStates.push(state);
	}
	for (var i = 0; i < nTxtCnt; i++) {
		state = new PDTextState();
		state.ParseFromBin(rd);
		this.textStates.push(state);

		var fontId = state.nFontID;
		if(this.m_pdDoc)this.m_usedFont.push(this.m_pdDoc.GetFontInfoByID(fontId));
	}
	// content stream
	var nObjStreamCnt = rd.readUint32();
	for (var i = 0; i < nObjStreamCnt; i++) {
		var nGeneralStateID, nClipStateID, nGraphStateID, nClrStateID, nTxtStateID;
		nGeneralStateID = rd.readUint16();
		nClipStateID = rd.readUint16();
		nGraphStateID = rd.readUint16();
		nClrStateID = rd.readUint16();
		nTxtStateID = rd.readUint16();
		var nObjCnt = rd.readInt32();
		var Obj = null;
		for (var j = 0; j < nObjCnt; j++) {
			var nObjType = rd.readByte();
			//rd.seek(-1, 2);
			switch(nObjType) {
				case 1: // text object
				Obj = new TextObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				this.textObjects.push(Obj);
				break;
				case 2: // image object
				Obj = new ImgObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				//this.LoadImage(Obj);
				break;
				case 3: // inline image object
				Obj = new InlineImgObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				//this.LoadImage(Obj);
				break;
				case 4: // path object
				Obj = new PathObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				break;
				case 5: // shading object
				Obj = new ShadingObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				break;
				case 6: // form object
				Obj = new FormObj(this);
				//Obj.m_pdPage = this.m_pdPage;
				Obj.ParseFromBin(rd);
				break;
				default:
				continue;
			}
			// set state IDs
			Obj.nGenStateID = nGeneralStateID;
			Obj.nClipPathStateID = nClipStateID;
			Obj.nGraphStateID = nGraphStateID;
		    Obj.nClrStateID = nClrStateID;
		    Obj.nTextStateID = nTxtStateID;
		    this.objectArr.push(Obj);
		    if (2 === nObjType || 3 === nObjType) {this.LoadImage(Obj);}
		}
	}
	// font info
//	if (this.type === 1) { // for form
		var nFontCnt = rd.readInt32();
		var fontInfo = null;
		for (var i = 0; i < nFontCnt; i++) {
			varfontInfo = new FontInfo();
			fontInfo.ParseFromBin(rd);
			this.fontInfo.push(fontInfo);
		}
//	}
    
	 this.m_BBox[0] = rd.readFloat32();
	 this.m_BBox[1] = rd.readFloat32();
	 this.m_BBox[2] = rd.readFloat32();
	 this.m_BBox[3] = rd.readFloat32();
	 
	 this.matrix = new PDMatrix();
	 var a = rd.readFloat32();
	 var b = rd.readFloat32();
	 var c = rd.readFloat32();
	 var d = rd.readFloat32();
	 var e = rd.readFloat32();
	 var f = rd.readFloat32();
	 this.matrix.Set(a, b, c, d, e, f);
     
	this.bFinishParseJson = true;
};

PDPageObjects.prototype.LoadImage = function(obj){
	this.imgObjCount += 1;
	obj.domImg = new Image();
	obj.domImg.pdPageObjs = this;
	obj.domImg.onload = PDPageObjects.prototype.OnImgLoaded;
	var imgUrl = this.m_csImgPath + obj.m_fileName;
	obj.domImg.src = imgUrl.charAt(0) == "/"?imgUrl.substr(1,imgUrl.length):imgUrl;
	obj.domImg.onerror = function(){
		obj.loadError = 1;
		PDPageObjects.prototype.OnImgLoaded.call(this);
	};
};

PDPageObjects.prototype.OnImgLoaded = function() {
	this.pdPageObjs.loadedImgObjCount += 1;
	if (!this.pdPageObjs.bFinishParseJson) {
		//this.pdPageObjs = null;
		return;
	}
	if (this.pdPageObjs.loadedImgObjCount < this.pdPageObjs.imgObjCount) {
		//this.pdPageObjs = null;
		return;
	}
	this.pdPageObjs.bFinishLoadImgs = true;
	if (null != this.pdPageObjs.callback && null != this.pdPageObjs.caller) {
		this.pdPageObjs.callback.call(this.pdPageObjs.caller);
	}
	//this.pdPageObjs = null;
};
